﻿
namespace CmdArgs
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using CmdArgs.Settings;

    /// <summary>
    /// Dictionary of options values.
    /// It can be indexed using any of option names - any of long 
    /// name aliases or short name aliases.
    /// </summary>
    public sealed class OptionsDictionary : IEnumerable<Option>
    {
        private IDictionary<string, Option> data = new Dictionary<string, Option>();
        private List<Option> dataAsList = new List<Option>();

        /// <summary>
        /// Gets the <see cref="CmdArgs.Option"/> with the specified name.
        /// The name might be one of option's aliases for long and short name.
        /// </summary>
        public Option this[string name]
        {
            get { return this.data[name]; }
        }

        /// <summary>
        /// Determines whether the dictionary contains option with the specified name.
        /// </summary>
        /// <param name="name">The name might be one of option's aliases for long and short name.</param>
        /// <returns>
        /// 	<c>true</c> if the dictionary contains the option with specified name; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(string name)
        {
            return this.data.ContainsKey(name);
        }

        /// <summary>
        /// Provides standard .NET way to ask for dictionary entry the safe way.
        /// It is combination of methods <see cref="Contains"/> and string indexer.
        /// </summary>
        /// <param name="name">The name might be one of option's aliases for long and short name.</param>
        /// <param name="option">The result of operation, if such option was not found than null.</param>
        /// <returns>
        /// 	<c>true</c> if the dictionary contains the option with specified name; otherwise, <c>false</c>.
        /// </returns>
        public bool TryGetOptionValue(string name, out Option option)
        {
            return this.data.TryGetValue(name, out option);
        }

        #region IEnumerable<Option> Members

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator<Option> GetEnumerator()
        {
            return this.dataAsList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return ((System.Collections.IEnumerable)this.dataAsList).GetEnumerator();
        }

        #endregion

        internal void AddOption(string name, Option option)
        {
            this.dataAsList.Add(option);
            this.data[name] = option;
        }

        internal void AddOption(Option option)
        {
            this.dataAsList.Add(option);
            foreach (var name in option.Settings.GetAllNames())
            {
                this.data[name] = option;
            }
        }
    }
}
